package com.zkh.myframe.database.mapper.parser;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.zkh.myframe.database.mapper.MapperEntity;
import com.zkh.myframe.database.mapper.MapperParseException;
import com.zkh.myframe.database.mapper.SQLEntity;
import com.zkh.myutils.utils.Assert;
import com.zkh.myutils.utils.StringUtils;

/**
 * 主解析器
 * @author zkh
 */
public class Parser {
	
	//待处理的临时命名空间和SQL对象存储
	static Map<String, Map<String, SQLEntity>> unDealSQLMap = new HashMap<String, Map<String, SQLEntity>>();
	
	/**
	 * 解析Mapper.xml文件
	 * @param root 根节点
	 * @param namespace 命名空间
	 * @return
	 */
	public static void renderMapper(Node root, String namespace, MapperEntity mapper) {
		//遍历第一级子节点
		Parser.eachChildren(root, node->{
			//标签名称
			String tagName = node.getNodeName();
			//文本节点，则跳过
			if("#text".equals(tagName) || "#comment".equals(tagName)){
				return;
			}
			//属性Map
			NamedNodeMap attr = node.getAttributes();
			//获取ID
			String id = attr.getNamedItem("id").getNodeValue();
			String dataSource = Assert.getIfNotNull(attr.getNamedItem("data-source"), Node::getNodeValue);
			//为空
			if(StringUtils.isEmpty(id)) {
				throw new MapperParseException("标签" + tagName + "的id不能为空");
			}
			//SQL标签
			if("sql".equalsIgnoreCase(tagName)) {
				mapper.addSQL(id, getSQLEntity(node, namespace, id, null, true));
			}else if("select".equalsIgnoreCase(tagName)){
				mapper.addSelect(id, getSQLEntity(node, namespace, id, dataSource, false));
			}else if("insert".equalsIgnoreCase(tagName)) {
				mapper.addInsert(id, getSQLEntity(node, namespace, id, dataSource, false));
			}else if("update".equalsIgnoreCase(tagName)) {
				mapper.addUpdate(id, getSQLEntity(node, namespace, id, dataSource, false));
			}else if("delete".equalsIgnoreCase(tagName)) {
				mapper.addDelete(id, getSQLEntity(node, namespace, id, dataSource, false));
			}
		});
	}
	
	/**
	 * 检查未处理的SQL
	 */
	public static void checkUnDealSQL() {
		//检查未处理的SQL标签是否处理完
		StringBuffer errors = new StringBuffer();
		//遍历异常
		unDealSQLMap.forEach((k, v)->{
			//遍历ID
			v.forEach((k1, v1) -> errors.append("；include标签引用的").append(v1.getNamespace()).append('.').append(v1.getId()).append(" 不存在"));
		});
		//如果有未处理完的SQL标签，且还在引用中，则抛出异常，如果未引用，则直接忽略
		if(!unDealSQLMap.isEmpty() && errors.length()>1) {
			throw new MapperParseException(errors.substring(1));
		}
	}
	
	/**
	 * 获取具体的SQLEntity对象（一级标签）
	 * @param node SQL标签节点
	 * @param namespace 命名空间
	 * @param id id值
	 * @param isSQLTag 是否是SQL标签
	 * @return
	 */
	private static SQLEntity getSQLEntity(Node node, String namespace, String id, String dataSource, boolean isSQLTag) {
		//创建对象
		SQLEntity sqlEntity = new SQLEntity(namespace, id, dataSource);
		//如果是SQL标签，从未处理的对象中获取对象
		if(isSQLTag) {
			// 获取未处理的SQL
			Map<String, SQLEntity> mapperMap = unDealSQLMap.get(namespace);
			//存在
			if(mapperMap!=null && mapperMap.containsKey(id)) {
				//保存并移除未处理记录
				sqlEntity = mapperMap.remove(id);
			}
		}
		//临时变量
		final SQLEntity tempSqlEntity = sqlEntity;
		//遍历子节点
		Parser.eachChildren(node, cnode->{
			//标签名称
			String tagName = cnode.getNodeName();
			//判断标签（include，trim，where，foreach，if或#text）
			if("#text".equals(tagName)) {
				tempSqlEntity.appendSQL(cnode.getTextContent().replaceAll("\\s+", " ").trim());
			}else if("include".equalsIgnoreCase(tagName)){
				tempSqlEntity.appendInclude(IncludeParser.parse(cnode, namespace));
				tempSqlEntity.appendSQL("{:include}");
			}else if("where".equalsIgnoreCase(tagName)) {
				tempSqlEntity.appendWhere(WhereParser.parse(cnode, namespace));
				tempSqlEntity.appendSQL("{:where}");
			}else if("foreach".equalsIgnoreCase(tagName)) {
				tempSqlEntity.appendForeach(ForeachParser.parse(cnode, namespace));
				tempSqlEntity.appendSQL("{:foreach}");
			}else if("if".equalsIgnoreCase(tagName)) {
				tempSqlEntity.appendIF(IfParser.parse(cnode, namespace));
				tempSqlEntity.appendSQL("{:if}");
			}else if("trim".equalsIgnoreCase(tagName)) {
				tempSqlEntity.appendTrim(TrimParser.parse(cnode, namespace));
				tempSqlEntity.appendSQL("{:trim}");
			}
		});
		//返回
		return sqlEntity;
	}
	
	/**
	 * 快速遍历节点的子节点
	 * @param node 需要遍历子节点的节点
	 * @param consumer 自定义子节点处理方法
	 */
	public static void eachChildren(Node node, Consumer<Node> consumer) {
		//遍历子节点
		if(node!=null) {
			//子节点
			NodeList list = node.getChildNodes();
			//遍历
			if(list!=null) {
				for(int i=0,len=list.getLength(); i<len; i++) {
					consumer.accept(list.item(i));
				}
			}
		}
	}
	
	/**
	 * 保存未处理的SQL标签
	 * @param namespace 命名空间
	 * @param id 方法名
	 * @param sqlEntity
	 */
	static void putUnDealSQL(String namespace, String id, SQLEntity sqlEntity) {
		//获取ID和标签映射
		Map<String, SQLEntity> idMap = unDealSQLMap.get(namespace);
		//不存在
		if(idMap==null) {
			//初始化
			idMap = new HashMap<String, SQLEntity>();
			//保存
			unDealSQLMap.put(namespace, idMap);
		}
		//存入
		idMap.put(id, sqlEntity);
	}
}
